﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using System.Xml;
using System.Threading;
using System.Windows.Forms;
using Google.GData.Client; 

namespace Utilities
{
    public delegate void DownloadCompleteEventHandler(string appPath);

    internal class UpdateUtilities
    {
        public Stream loadFromWeb(string url)
        {
            HttpWebResponse response;

            //Retrieve the File
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Proxy = Google.GData.Client.Utilities.CommonOperations.GetProxy();
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException e)
            {
                TraceWrapper.LogException("loadManifest error: " + e.Message, e);

                if (e.Response == null)
                    throw;

                HttpWebResponse errorResponse = (HttpWebResponse)e.Response;

                //if the file has not been modified -it's expected behavior that we get such exception
                if (errorResponse.StatusCode == HttpStatusCode.NotModified)
                {
                    e.Response.Close();
                    throw;
                }
                else
                {
                    e.Response.Close();
                    throw;
                }
            }

            return response.GetResponseStream();
        }

        public string parseLocalManifest(string localManifest, string appName, string tagName)
        {
            try
            {
                XmlDocument manifest = new XmlDocument();
                manifest.Load(localManifest);
                XmlNodeList appNodeList = manifest.GetElementsByTagName("ApplicationName");

                foreach (XmlNode appNode in appNodeList)
                    foreach (XmlAttribute attr in appNode.Attributes)
                        if (attr.InnerText == appName)
                        {
                            foreach (XmlNode node in appNode.ChildNodes)
                                if (node.Name == tagName)
                                    return node.InnerXml;
                        }
                
                //return manifest.GetElementsByTagName(tagName)[0].InnerText;
            }
            catch (System.Exception e)
            {
                TraceWrapper.LogException("parseManifest error: " + e.Message, e);
            }

            return "0.0.0.0";
        }
    }

    internal class Updater
    {
        private UpdateUtilities m_util = new UpdateUtilities();
        private Downloader m_downloader;
        private Thread m_updateThread;
        private string m_appName;
        private string m_version;

        public Updater(string appName, string version)
        {
            m_appName = appName;
            m_version = version;
        }

        public void loadManifest(string url, string localPath)
        {
            Stream stream = m_util.loadFromWeb(url);
            CommonOperations.DoSaveContent(stream, localPath);
        }

        public bool isNewVersionExist(string localManifest, string appName)
        {
            string vs = m_util.parseLocalManifest(localManifest, appName, "AvailableVersion");
            Version version = new Version(vs);
            return (version > new Version(m_version));
        }

        public void downloadNewVersion(string url, string localPath, DownloadCompleteEventHandler completedCb)
        {
            m_downloader = new Downloader(url, localPath, completedCb);
            m_downloader.Start();
        }

        private void runInstall(string appPath)
        {
            System.Diagnostics.Process.Start(appPath);
        }

        private void RunThread()
        {
            try
            {
                string manifestUrl = "http://www.upriseapps.com/downloads/UpdateManifest.xml";
                string manifestPath = System.IO.Path.GetTempPath() + System.IO.Path.GetFileName(manifestUrl);
                loadManifest(manifestUrl, manifestPath);

                if (isNewVersionExist(manifestPath, m_appName))
                {
                    DialogResult dr = MessageBox.Show("The new version of Office in Cloud available. Do you want to install it?", "Office in Cloud", MessageBoxButtons.YesNo);
                    if (dr == DialogResult.Yes)
                    {
                        string appUrl = m_util.parseLocalManifest(manifestPath, m_appName, "ApplicationUrl");
                        string appPath = System.IO.Path.GetTempPath() + System.IO.Path.GetFileName(appUrl);
                        DownloadCompleteEventHandler completedCb = new DownloadCompleteEventHandler(runInstall);

                        downloadNewVersion(appUrl, appPath, completedCb);
                    }
                }
            }
            catch (Exception ex)
            {
                TraceWrapper.LogException("checkForUpdates error: " + ex.Message, ex);
            }
        }

        public void Start()
        {
            m_updateThread = new Thread(new ThreadStart(RunThread));
            m_updateThread.Name = "Updater Thread";

            if (!m_updateThread.IsAlive)
                m_updateThread.Start();
        }
    }

    internal class Downloader
    {
        private Thread m_downloadThread;
        private string m_url;
        private string m_localPath;
        
        public event DownloadCompleteEventHandler onDownloadComplete;

        public Downloader(string _url, string localPath, DownloadCompleteEventHandler completedCb)
        {
            m_url = _url;
            m_localPath = localPath;
            onDownloadComplete = completedCb;
        }

        private void RunThread()
        {
            UpdateUtilities webUtil = new UpdateUtilities();
            Stream fs = webUtil.loadFromWeb(m_url);
            CommonOperations.DoSaveContent(fs, m_localPath);

            onDownloadComplete(m_localPath);
        }

        public void Start()
        {
            m_downloadThread = new Thread(new ThreadStart(RunThread));
            m_downloadThread.Name = "Downloader Thread";

            if (!m_downloadThread.IsAlive)
                m_downloadThread.Start();
        }
    }

    public class Update
    {
        Updater m_updater;

        public void checkForUpdates(string appName, string version)
        {
            m_updater = new Updater(appName, version);
            m_updater.Start();
        }
    }
}
